#include "TimestampUtil.h"

int TimestampUtil::checkBitLength(time_t timestamp)
{
    int bit = 0;
    if (timestamp == 0)
        return 1;

    while (timestamp)
    {
        bit++;
        timestamp /= 10;
    }
    return bit;
}

std::chrono::system_clock::time_point TimestampUtil::_getNow()
{
    return std::chrono::system_clock::now();
}

int TimestampUtil::getTimeLevel(const time_t &timestamp)
{
    int timestampLen = checkBitLength(timestamp);

    int time_level = -1;
    switch (timestampLen)
    {
        case 10:
            time_level = 0;
            break;

        case 13:
            time_level = 1;
            break;

        case 16:
            time_level = 2;
            break;

        case 19:
            time_level = 3;
            break;

        default:
            break;
    }

    return time_level;
}


void TimestampUtil::setFormatData(int time_level, const std::string &formatType, struct __timeData &timedata)
{
    time_t timestamp = timedata.timestamp;


    time_t timestamp_sec;
    std::stringstream formatTime;
    switch (time_level)
    {

        case 0:
            timestamp_sec = timestamp;

            break;

        case 1:
            timestamp_sec = timestamp / 1000;

            timedata.ms = timestamp % 1000;

            break;

        case 2:
            timestamp_sec = timestamp / 1000 / 1000;

            timedata.cs = timestamp % 1000;
            timedata.ms = timestamp / 1000 % 1000;

            break;

        case 3:
            timestamp_sec = timestamp / 1000 / 1000 / 1000;

            timedata.ns = timestamp % 1000;
            timedata.cs = timestamp / 1000 % 1000;
            timedata.ms = timestamp / 1000 / 1000 % 1000;

            break;

        default:

            return;
    }
    tm timeInfo;

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
    localtime_s(&timeInfo, &timestamp_sec);
#elif defined(linux) || defined(__linux) || defined(__linux__)
    localtime_r(&timestamp_sec, &timeInfo);
#elif defined(unix) || defined(__unix) || defined(__unix__)
    localtime_r(&timestamp_sec, &timeInfo);
#endif

    formatTime << std::put_time(&timeInfo, formatType.c_str());
    timedata.formatDatatime = formatTime.str();
}

std::string TimestampUtil::buildFormatString(struct __timeData &timedata)
{
    std::stringstream formatString;
    formatString << timedata.formatDatatime;

    if (timedata.ms == -1)
    {
        return formatString.str();
    }
    formatString << " " << std::setw(3) << std::setfill('0') << timedata.ms;


    if (timedata.cs == -1)
    {
        return formatString.str();
    }
    formatString << "." << std::setw(3) << std::setfill('0') << timedata.cs;


    if (timedata.ns == -1)
    {
        return formatString.str();
    }
    formatString << "." << std::setw(3) << std::setfill('0') << timedata.ns;
    return formatString.str();
}

time_t TimestampUtil::getCurrentTimestamp(int time_level)
{

    auto timeinfo = _getNow().time_since_epoch();
    time_t current_time_stamp;
    using namespace std::chrono;
    switch (time_level)
    {

        case 0:
            current_time_stamp = duration_cast<std::chrono::seconds>(timeinfo).count();
            break;
        case 1:
            current_time_stamp = duration_cast<std::chrono::milliseconds>(timeinfo).count();
            break;
        case 2:
            current_time_stamp = duration_cast<std::chrono::microseconds>(timeinfo).count();
            break;
        case 3:
            current_time_stamp = duration_cast<std::chrono::nanoseconds>(timeinfo).count();
            break;
        default:
            current_time_stamp = -1;
            break;
    }
    return current_time_stamp;
}

std::string TimestampUtil::getCurrentFormatDatetime(int time_level)
{
    struct __timeData timedata;
    timedata.timestamp = getCurrentTimestamp(time_level);
    setFormatData(time_level, "%Y-%m-%d %H:%M:%S", timedata);
    return buildFormatString(timedata);
}

std::string TimestampUtil::getCurrentFormatDate()
{
    struct __timeData timedata;
    timedata.timestamp = getCurrentTimestamp(0);
    setFormatData(0, "%Y-%m-%d", timedata);

    return buildFormatString(timedata);
}

std::string TimestampUtil::getCurrentFormatTime()
{
    struct __timeData timedata;
    timedata.timestamp = getCurrentTimestamp(0);

    setFormatData(0, "%H:%M:%S", timedata);

    return buildFormatString(timedata);
}

std::string TimestampUtil::getFormatData(const time_t timestamp)
{
    struct __timeData timedata;
    int time_level = getTimeLevel(timestamp);
    timedata.timestamp = timestamp;
    time_level = 0;
    time_level = timestampGabFix(time_level, timedata);
    setFormatData(time_level, "%Y-%m-%d", timedata);

    return buildFormatString(timedata);
}

std::string TimestampUtil::getFormatTime(const time_t timestamp)
{
    struct __timeData timedata;
    int time_level = getTimeLevel(timestamp);
    timedata.timestamp = timestamp;
    time_level = 0;
    time_level = timestampGabFix(time_level, timedata);
    setFormatData(time_level, "%H:%M:%S", timedata);

    return buildFormatString(timedata);
}

std::string TimestampUtil::getFormatDataTime(time_t timestamp, int time_level)
{


    // cout << "input time_value = " << time_level << endl;

    if (time_level > 3 || time_level < 0)
    {
        return nullptr;
    }
    // cout  << timestamp << endl;

    struct __timeData timedata;
    timedata.timestamp = timestamp;

    // timestamp和time_level的精度拟合修复函数
    time_level = timestampGabFix(time_level, timedata);

    setFormatData(time_level, "%Y-%m-%dT%H:%M:%S", timedata);

    return buildFormatString(timedata);
}

int TimestampUtil::timestampGabFix(int input_level, __timeData &timedata)
{

    int time_level_gab;   // 拟合值

    time_t timestamp = timedata.timestamp;


    int timestamp_time_level = getTimeLevel(timestamp);


    if (timestamp_time_level < 0)
    {
        return -1;
    }
    int time_level = -1;

    // 时间戳精度大于输入精度, 时间戳根据插值删减
    if (timestamp_time_level > input_level)
    {
        time_level_gab = timestamp_time_level - input_level;
        timestamp = (time_t)(timestamp / pow(1000, time_level_gab));   // 时间戳截取
        time_level = input_level;                                      // 使用输入的精度

        // cout << "timestamp_time_level = " << timestamp_time_level << endl;
        // cout << "input_level = " << input_level << endl;
    }
        // 时间戳精度小于输入精度, 以时间戳精度为准
    else
    {
        time_level = timestamp_time_level;
    }



    timedata.timestamp = timestamp;

    return time_level;
}

